/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package personal.parser;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomAttr;
import com.gargoylesoftware.htmlunit.html.DomText;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.LogFactory;
import personal.parseInfo.TolkienParseInfo;
import personal.pojo.tolkien.Book;
import personal.pojo.tolkien.Category;
import personal.utility.TolkienDBUtility;

/**
 *
 * @author PHATNBSE61057
 */
public class TolkienParser {

    private TolkienParseInfo info;
    private WebClient webClient;

    public TolkienParser() {
        LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log",
                "org.apache.commons.logging.impl.NoOpLog");
        webClient = new WebClient(BrowserVersion.FIREFOX_24);
        webClient.getOptions().setThrowExceptionOnScriptError(false);
        webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
    }

    public void setWebParseInfo(TolkienParseInfo parseInfo) {
        this.info = parseInfo;
    }

    public List<Category> getCategories() {
        try {
            List<Category> categories = new ArrayList<>();
            HtmlPage page = webClient.getPage(info.getParsePage());
            List<HtmlElement> allCategories = (List<HtmlElement>) page.getByXPath(info.getCategoriesXPath());
            for (HtmlElement category : allCategories) {
                String categoryLink = category.getAttribute("href").trim();
                DomText nameText = category.getFirstByXPath(info.getCategoriesNameXPath());
                try {
                    String categoryName = nameText.getTextContent().trim();
                    Category cate = new Category(categoryName, categoryLink, info.getWebPage());
                    categories.add(cate);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
            System.out.println(categories.size() + " categories found.");
            return categories;
        } catch (IOException | FailingHttpStatusCodeException e) {
            System.out.println(e);
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }

    public List<Book> getBooks() {
        TolkienDBUtility dBUtility = new TolkienDBUtility();
        List<Category> categories = dBUtility.tolkienLoadCategory();
        List<Book> books = new ArrayList<>();
        for (Category cate : categories) {
            books.addAll(getBooksByCategories(cate));
        }
        return books;
    }

    public List<Book> getBooks(int... categoryIndexs) {
        TolkienDBUtility dBUtility = new TolkienDBUtility();
        List<Category> categories = dBUtility.tolkienLoadCategory();
        List<Book> books = new ArrayList<>();
        for (int i = 0; i < categoryIndexs.length; i++) {
            int categoryIndex = categoryIndexs[i];
            if (categoryIndex < categories.size()) {
                books.addAll(getBooksByCategories(categories.get(categoryIndex)));
            } else {
                System.out.println(categoryIndex + " out of array.");
            }
        }
        return books;
    }

    public List<Book> getBooksByCategories(Category inCate) {
        try {
            /*null
             * Identify two List which are [links] and [thumbs]
             * which is contains all links to book details and
             * all links of books's thumbs
             */
            List<String> links = new ArrayList<>();
            List<String> thumbs = new ArrayList<>();
            List<Book> books = new ArrayList<>();
            Book book = new Book();
            HtmlPage bookPage = null;
            boolean flag = true;
            System.out.println("Get books of category: " + inCate.getCategoryName() + " ID: " + inCate.getCategoryID());
            //Parse trang category
            HtmlPage categoryPage = webClient.getPage(inCate.getCategoryLink());
            //Bắt đầu vòng lặp để lấy toàn bộ thông tin từ các trang
            do {
                //Catch all books display on this page
                List<HtmlElement> singleBookDivs = (List<HtmlElement>) categoryPage.getByXPath(info.getAllBooksXPath());

                //Get all Links and Thumb of all books parsed
                for (HtmlElement bookDiv : singleBookDivs) {
                    DomAttr linkAttr = bookDiv.getFirstByXPath(info.getBooksLinkXPath());
                    DomAttr thumbAttr = bookDiv.getFirstByXPath(info.getBooksThumbXPath());
                    //Get value of DomAttribute parsed
                    try {
                        String bookLink = linkAttr.getValue().trim();
                        String bookThumb = thumbAttr.getValue().trim();
                        if (!bookLink.contains("http")) {
                            bookLink = info.getWebPage() + bookLink;
                        }
                        if (!bookThumb.contains("http")) {
                            bookThumb = info.getWebPage() + bookThumb;
                        }
                        links.add(bookLink);
                        thumbs.add(bookThumb);
                    } catch (NullPointerException e) {
                        System.out.println(e);
                    }
                }
                //Catch next button for the next page
                //Cách 1
                HtmlElement element = (HtmlElement) categoryPage.getFirstByXPath(info.getNextButton());
                if (element != null) {
                    categoryPage = element.click();
                } else {
                    flag = false;
                }
                /*
                 * Cách 2
                 * System.out.println("Continue next page");
                 HtmlElement nextButton = (HtmlElement) webPage.getFirstByXPath(info.getNextButton());
                 if (nextButton != null) {
                 String javascript = nextButton.getAttribute("href").trim();
                 ScriptResult result = webPage.executeJavaScript(javascript);
                 webPage = (HtmlPage) result.getNewPage();
                 System.out.println("Finish load new page");
                 } else {
                 flag = false;
                 }
                 */
            } while (flag); //Kết thúc vòng lặp
            System.out.println(links.size() + " links");
            /* 
             * Để lấy thông tin của sách thì có 2 phương án
             * Phương án 1: Lấy hết toàn bộ link rồi sau đó vào từng link lấy thông tin
             * Phương án 2: Lấy được link nào vào xử lý link đó.
             * Chọn phương án 1!!!
             */
            //Đi vào từng link để làm việc

            //Khai báo biến dùng cho book's info.
            List<DomText> infoTexts = new ArrayList<>();
            List<DomText> desTexts = new ArrayList<>();

            for (int i = 0; i < links.size(); i++) {
                //Lấy toàn bộ trang detail của 1 quyển sách
                bookPage = webClient.getPage(links.get(i));
                //Lấy thông tin
                DomText nameText = bookPage.getFirstByXPath(info.getBooksNameXPath());
                DomAttr imgAttr = bookPage.getFirstByXPath(info.getBooksImg());
                DomText priceText = bookPage.getFirstByXPath(info.getBooksPriceXPath());
                infoTexts = (List<DomText>) bookPage.getByXPath(info.getBooksInfoXPath());
                desTexts = (List<DomText>) bookPage.getByXPath(info.getBooksDescription());
                try {
                    //Lấy toàn bộ giá trị trong các DOM đã parsed được
                    String bookName = nameText.getTextContent().trim();
                    //2 thông số tiếp theo được lấy từ trước bên ngoài
                    String bookLink = links.get(i);
                    String bookThumb = thumbs.get(i);
                    //--------------------------------
                    // Lấy hai thông số bên trong cùng với name
                    String bookImg = imgAttr.getValue().trim();
                    String bookPrice = priceText.getTextContent().trim();
                    //--------------------------------
                    String bookPages = "";
                    String bookFormat = "";
                    String bookAuthor = "";
                    String bookPublished = "";
                    String bookISBN = "";
                    String bookDetailedEdition = "";
                    String bookDescription = "";
                    //--------------------------------
                    // Lấy thông tin chi tiết
                    for (int j = 0; j < infoTexts.size() - 1; j++) {
                        String detail = infoTexts.get(j).getTextContent().trim();
                        if (detail.contains("Pages")) {
                            bookPages = infoTexts.get(1 + j).getTextContent().trim();
                        } else if (detail.contains("Format")) {
                            bookFormat = infoTexts.get(1 + j).getTextContent().trim();
                        } else if (detail.contains("Author")) {
                            bookAuthor = infoTexts.get(1 + j).getTextContent().trim();
                        } else if (detail.contains("Published")) {
                            bookPublished = infoTexts.get(1 + j).getTextContent().trim();
                        } else if (detail.contains("ISBN")) {
                            bookISBN = infoTexts.get(1 + j).getTextContent().trim();
                        } else if (detail.contains("Detailed")) {
                            bookDetailedEdition = infoTexts.get(1 + j).getTextContent().trim();
                        }
                    }
                    //--------------------------------
                    // Lấy description
                    for (DomText desText : desTexts) {
                        String description = desText.getTextContent().trim();
                        bookDescription = bookDescription + description + ";";
                    }
                    bookDescription = bookDescription.substring(0, bookDescription.length() - 1);
                    //New một book
                    book = new Book(inCate.getCategoryID(), bookName, bookLink,
                            bookThumb, bookImg, bookPrice, bookPages,
                            bookFormat, bookAuthor, bookPublished, bookISBN,
                            bookDetailedEdition, bookDescription,
                            info.getWebPage());
                    //-------------------------------------
                    //Add sách mới vào lô
                    book.setBookID("000001");
                    books.add(book);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
            return books;
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
    }
}
